﻿
//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////

#include "SamplePickPointAction.h"
#include "IPick.h"
#include "ISnap.h"
#include "IPlane.h"
#include "IUiView.h"
#include "IPicker.h"
#include "Snapper.h"
#include "ILine3d.h"
#include "ICommand.h"
#include "IDocument.h"
#include "IModelView.h"
#include "UiViewUtils.h"
#include "IUiDocument.h"
#include "UiSnapUtils.h"
#include "ISnapRender.h"
#include "GbmpWindows.h"
#include "IPickTarget.h"
#include "JournalUtils.h"
#include "ISnapContext.h"
#include "Vector3dUtils.h"
#include "UIRenderUtils.h"
#include "ISnapSettings.h"
#include "IActionManager.h"
#include "ILineEditEvent.h"
#include "IPreHighlights.h"
#include "IGraphicsPlane.h"
#include "IPickCandidates.h"
#include "ISnapCandidates.h"
#include "IPickCandidates.h"
#include "ICommandManager.h"
#include "AlgorithmProject.h"
#include "GcmpCommandNames.h"
#include "CommandParameters.h"
#include "IUiViewMouseEvent.h"
#include "ILineEditEventArgs.h"
#include "AlgorithmIntersect.h"
#include "IElementShapeHandle.h"
#include "UiNotificationUtils.h"
#include "IElementShapeHandle.h"
#include "IUiViewMouseEventArgs.h"
#include "IUiDocumentViewManager.h"
#include "IPickPointActionConfig.h"
#include "IGraphicsNodeReference.h"
#include "IUiViewMouseEventHandler.h"
#include "IPickPointActionOutputData.h"
#include "ICoordinateInputDefinition.h"
#include "ICommandMenuItemDefinition.h"
#include "ITemporaryDimensionManager.h"
#include "ITemporaryDimensionHandler.h"
#include "IElementShapeHandleBehavior.h"
#include "IActionCoordinateInputWidget.h"
#include "IMenuItemContainerDefinition.h"
#include "TemporaryDimensionCommonsUtils.h"

//#include "DocUtil.h"
//#include "RenderUtils.h"
//#include "GIntersector.h"
//#include "AuxiliaryElement.h"
//#include "PerformanceTimer.h"
#include "TemporaryDimensionCommons.h"
#include "PickPointActionOutputData.h"
#include "Pick\PickAction\PickFilter.h"
//#include "TemporaryDimensionManager.h"
#include "DefaultPickFilterForLocalSnap.h"
#include "DefaultPickFilterForRemoteSnap.h"
#include "Pick\PickAction\SamplePickActionBase.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;
using namespace Sample;
// using namespace gcmp::ViewerUtil;

static const bool UseSnapEdgeLineExtension;
static const bool DisableActionCoordinateInput = false;
static const bool SnapDirDeterminedByModelView = false;
static const bool Snap3DAxialDirectionLine = false;
static const bool OpenSnap3DParallel = false;
static const bool OpenSmartColorForSnapPrompt = false;
static const bool CloseRemoteSnapsDeduplication = false;
static const bool SnapTangencyPointWhenCondition = false;

// 视图内临时动态尺寸相关
#define    ID_CMD_VIEW_INPUT_EDIT_VALUE_CONFIRM   L"gmConfirmViewInputEditValue" //确认
#define    ID_CMD_VIEW_INPUT_EDIT_VALUE_CANCEL   L"gmCancelHandlerEditValue" //取消

namespace
{
    class AuxiliaryElementPickFilter : public Sample::PickFilter
    {
    public:
        AuxiliaryElementPickFilter(const IDocument* pDocument, const std::vector<std::wstring>& activatableCommands)
            : PickFilter(pDocument)
            , m_activatableCommands(activatableCommands)
        {}
        virtual ~AuxiliaryElementPickFilter(){}

        // 是否允许拾取此Element GRep及其子节点
        virtual bool AllowElement(const ElementId& elemId) const override;

    private:
        std::vector<std::wstring> m_activatableCommands;
    };

    bool AuxiliaryElementPickFilter::AllowElement(const ElementId& elemId) const
    {
        IElementShapeHandle* pElementShapeHandle = quick_cast<IElementShapeHandle>(GetDocument()->GetElement(elemId));
        if (pElementShapeHandle)
        {
            std::wstring commandAttached;
            gcmp::CommandParameters cmdParams;
            if (pElementShapeHandle && pElementShapeHandle->GetElementShapeHandleBehavior() && 
                    pElementShapeHandle->GetElementShapeHandleBehavior()->GetHandleCommandString(nullptr,commandAttached, cmdParams))
            {
                return ValueContainerUtil::IsInContainer(m_activatableCommands, commandAttached);
            }
        }

        return false;
    }

    class UiViewMouseEventHandler : public IUiViewMouseEventHandler
    {
    public:
        UiViewMouseEventHandler(IActionCoordinateInputWidget* pCoordWidget) : m_pCoordWidget(pCoordWidget)
        {
        }
        virtual void On(IUiViewMouseEventArgs* pArgs) override;
    private:
        WeakPtr<IActionCoordinateInputWidget> m_pCoordWidget;
    };
}

SamplePickPointAction::SamplePickPointAction(
    PickPointExchangeData &exchangeData, 
    IPickPointAction::MoveCallback moveCallback/* = nullptr*/,
    ActionFinishedMode enActionFinishedMode/* = ActionFinishedMode::LButtonDown*/,
    bool isReturnKeyNeedCanceled, 
    OwnerPtr<IPickPointActionConfig> opPickConfig)
    : m_pped(exchangeData)
    , m_moveCallback(moveCallback)
    , m_isCaught(false)
    , m_IsTabReset(false)
    , m_enActionFinishedMode(enActionFinishedMode)
    , m_OnKeyDownCallback(nullptr)
    , m_cursorPathCallBack(nullptr)
    , m_opPickPointActionConfigure(TransferOwnership(opPickConfig))
{
    SetCursorType(CursorType::CrossCursor);
    m_opSnapContext = ISnapContext::Create();
    SetReturnKeyNeedCanceled(isReturnKeyNeedCanceled);
}

SamplePickPointAction::~SamplePickPointAction()
{
    CleanupTempGraphicsShape();

    if (m_opViewMouseHandler)
    {
        IUiView* pCurrentUiView = IUiDocumentViewManager::Get()->GetCurrentUiView();
        if (pCurrentUiView)
        {
            if (IUiViewMouseEvent* pUiViewMouseEvent = pCurrentUiView->GetUiViewMouseEvent())
            {
                pUiViewMouseEvent->Delete(m_opViewMouseHandler.get());
            }
        }
    }

    // 在这只做隐藏操作，该窗口由其父对象来进行销毁
    if (m_opCoordinateInputWidget)
    {
        m_opCoordinateInputWidget->HideAndClear();
    }
}

void SamplePickPointAction::InitAction(IUiView* pCurrentView)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(pCurrentView, L"空指针pCurrentView",L"GDMP",L"2024-03-30");
    //清除预高亮集
    IPreHighlights::Get()->Clear();
    IPickCandidates::Get()->Clear();
    if(!m_opSnapContext->GetFilterForLocalSnap())
    {
        m_oFilterForLocalSnap = NEW_AS_OWNER_PTR(DefaultPickFilterForLocalSnap, GetDoc());
        m_opSnapContext->SetFilterForLocalSnap(m_oFilterForLocalSnap.get());
    }
    if (!m_opSnapContext->GetFilterForRemoteSnap())
    {
        m_oFilterForRemoteSnap = NEW_AS_OWNER_PTR(DefaultPickFilterForRemoteSnap, GetDoc());
        m_opSnapContext->SetFilterForRemoteSnap(m_oFilterForRemoteSnap.get());
    }
}

OwnerPtr<IAction> ExecuteCommand(const std::wstring& cmdName, const gcmp::CommandParameters& cmdParams)
{
    ICommand* pCommand = ICommandManager::Get()->GetCommand(cmdName);

    DBG_WARN_AND_RETURN_UNLESS(pCommand && pCommand->IsEnabled() && pCommand->IsVisible(), nullptr, L"必需保证当前命令执行环境正确！",L"GDMP",L"2024-03-30");
    return pCommand->ExecuteCommand(cmdParams);
}

bool SamplePickPointAction::OnLButtonDown( IUiView* pCurrentView,const Vector3d& pos )
{   
    // 如果临时尺寸标注还处在编辑状态，则直接提交输入作为拾取结果
    ITemporaryDimensionManager *pTemporaryDimensionMgr = ITemporaryDimensionManager::Get();
    if (pTemporaryDimensionMgr)
    {
        ITemporaryDimensionHandler *pITemporaryDimensionHandler = pTemporaryDimensionMgr->GetCurrentTemporaryDimensionHandler();
        if (pITemporaryDimensionHandler && pITemporaryDimensionHandler->IsInInputState())
        {
            pITemporaryDimensionHandler->OnEditorReturnPressed();
            return true;
        }
    }

    // 左键点击取消坐标输入
    if (m_opCoordinateInputWidget)
    {
        m_opViewMouseHandler.reset(nullptr);
    }

    const GraphicsNodeReferenceOwnerPtrVector& candidate = IPickCandidates::Get()->GetCurrentPick()->GetAllGraphicsNodeReferences();
    if (candidate.size() == 1)
    {
        IModelView* pModelView = pCurrentView->GetModelView();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pModelView, L"view为空",L"GDMP",L"2024-03-30");

        IDocument* pDoc = pModelView->GetDocument();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc != nullptr, L"无效的文档",L"GDMP",L"2024-03-30");

        ElementId id = candidate.at(0)->GetElementId();
        IElement* pElement = pDoc->GetElement(id);
        IElementShapeHandle* pShapeHandle = quick_cast<IElementShapeHandle>(pElement);

        if (pShapeHandle)
        {
            std::wstring commandAttached;
            gcmp::CommandParameters cmdParams;
            if (pShapeHandle && pShapeHandle->GetElementShapeHandleBehavior() && 
                pShapeHandle->GetElementShapeHandleBehavior()->GetHandleCommandString(nullptr,commandAttached, cmdParams))
            {
                if (ValueContainerUtil::IsInContainer(m_pped.activatableCommands, commandAttached))
                {
                    OwnerPtr<IAction> opChildAction = ExecuteCommand(commandAttached, cmdParams);
                    if(opChildAction)
                    {
                        StartChildAction(TransferOwnership(opChildAction));
                        return true;
                    }
                }
            }
        }
    }
    //右键结束模式下，左键也结束
    if (m_enActionFinishedMode == ActionFinishedMode::RButtonDown ||
        m_enActionFinishedMode == ActionFinishedMode::RButtonUp ||
        m_enActionFinishedMode == ActionFinishedMode::LButtonDown)
    {
        m_pped.pPickedPoints->push_back(*m_pped.pPickedPoint);
        ISnapRender::Get()->ClearSnapRenderData();
        SAFE_INIT_POINTER(m_pped.pUserCancelled, false);
        UpdateView();
        MarkFinishStatus(ActionFinishStatus::Successful);
    }

    return true;
}

bool SamplePickPointAction::OnLButtonUp( IUiView* pCurrentView,const Vector3d& pos )
{
    if (m_enActionFinishedMode == ActionFinishedMode::LButtonUp)
    {
        ISnapRender::Get()->ClearSnapRenderData();
        SAFE_INIT_POINTER(m_pped.pUserCancelled, false);
        UpdateView();

        MarkFinishStatus(ActionFinishStatus::Successful);
    }

    return true;
}

bool SamplePickPointAction::OnRButtonDown(gcmp::IUiView* pCurrentView, const gcmp::Vector3d& pos)
{
    if (m_enActionFinishedMode == ActionFinishedMode::RButtonDown)
    {
        ISnapRender::Get()->ClearSnapRenderData();
        SAFE_INIT_POINTER(m_pped.pUserCancelled, false);
        UpdateView();
        MarkFinishStatus(ActionFinishStatus::Cancelled);
        MarkFinishReason(ActionFinishReason::RButtonDown);
        return true;
    }

    if (m_opCoordinateInputWidget)
    {
        m_opViewMouseHandler.reset(nullptr);
    }
    return ActionBase::OnRButtonDown(pCurrentView, pos);
}

OwnerPtr<gcmp::IMenuItemContainerDefinition> SamplePickPointAction::PrepareContextMenu(IUiView* pUIView)
{
    ITemporaryDimensionManager *pTemporaryDimensionMgr = ITemporaryDimensionManager::Get();
    if (pTemporaryDimensionMgr)
    {
        ITemporaryDimensionHandler *pITemporaryDimensionHandler = pTemporaryDimensionMgr->GetCurrentTemporaryDimensionHandler();
        if (pITemporaryDimensionHandler && pITemporaryDimensionHandler->IsInInputState())
        {
            const std::wstring handlerEditingMenuId = L"HandlerEditingMenu";
            OwnerPtr<IMenuItemContainerDefinition> pMenuItemContainer = IMenuItemContainerDefinition::Create(handlerEditingMenuId, L"");

            {
                OwnerPtr<IMenuItemDefinition> pDefMenuItem = ICommandMenuItemDefinition::Create(ID_CMD_VIEW_INPUT_EDIT_VALUE_CONFIRM, ID_CMD_VIEW_INPUT_EDIT_VALUE_CONFIRM, GBMP_TR(L"确定"), GBMP_TR(L"确定"), L"");
                pMenuItemContainer->AddSubMenuItem(TransferOwnership(pDefMenuItem));
            }
            {
                OwnerPtr<IMenuItemDefinition> pDefMenuItem = ICommandMenuItemDefinition::Create(ID_CMD_VIEW_INPUT_EDIT_VALUE_CANCEL, ID_CMD_VIEW_INPUT_EDIT_VALUE_CANCEL, GBMP_TR(L"取消"), GBMP_TR(L"取消"), L"");
                pMenuItemContainer->AddSubMenuItem(TransferOwnership(pDefMenuItem));
            }

            return TransferOwnership(pMenuItemContainer);
        }
    }

    if (m_enActionFinishedMode != ActionFinishedMode::RButtonDown &&
        m_enActionFinishedMode != ActionFinishedMode::RButtonUp)
    {
        const std::wstring defActionMenuId = L"DefActionMenu";
        OwnerPtr<IMenuItemContainerDefinition> pMenuItemContainer = IMenuItemContainerDefinition::Create(defActionMenuId, L"");
        {
            OwnerPtr<IMenuItemDefinition> pDefMenuItem = ICommandMenuItemDefinition::Create(ID_CMD_ACTION_CONFIRM, ID_CMD_ACTION_CONFIRM, GBMP_TR(L"确定"), GBMP_TR(L"确定"), L"");
            pMenuItemContainer->AddSubMenuItem(TransferOwnership(pDefMenuItem));
        }
        {
            OwnerPtr<IMenuItemDefinition> pDefMenuItem = ICommandMenuItemDefinition::Create(ID_CMD_ACTION_ESCAPE, ID_CMD_ACTION_ESCAPE, GBMP_TR(L"取消"), GBMP_TR(L"取消"), L"");
            pMenuItemContainer->AddSubMenuItem(TransferOwnership(pDefMenuItem));
        }

        return TransferOwnership(pMenuItemContainer);
    }
    return nullptr;
}

bool SamplePickPointAction::OnRButtonUp(gcmp::IUiView* pCurrentView, const gcmp::Vector3d& pos)
{
    if (m_enActionFinishedMode == ActionFinishedMode::RButtonUp)
    {
        ISnapRender::Get()->ClearSnapRenderData();
        SAFE_INIT_POINTER(m_pped.pUserCancelled, false);
        UpdateView();
        MarkFinishStatus(ActionFinishStatus::Cancelled);
        MarkFinishReason(ActionFinishReason::RButtonUp);
        return true;
    }
    return ActionBase::OnRButtonUp(pCurrentView,pos);
}

void SamplePickPointAction::DoPick(IUiView* pCurrentView, const Vector3d& pos)
{
    //捕捉过程中，拾取平面上的辅助对象
    int screenX,screenY;
    float depth;
    UiViewUtility::WorldPositionToScreenPosition(pCurrentView, pos, screenX, screenY, depth);

    IDocument*pDocument = pCurrentView->GetUiDocument()->GetDbDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDocument, L"pDocument不能为空",L"GDMP",L"2024-03-30");

    AuxiliaryElementPickFilter pickFilter(pDocument, m_pped.activatableCommands);
    OwnerPtr<IPickTarget> opPickTarget = gcmp::IPickTarget::Create();
    opPickTarget->DisableAll();
    opPickTarget->EnableGraphicsElementShape();

    //做一次拾取，并更新全局的选择集
    PickActionUtil::UpdateCandidatesSingleton(pCurrentView, screenX, screenY, pos, nullptr, &pickFilter, opPickTarget.get(), true, true, m_pixelCount);
        
}

void SamplePickPointAction::DoSnap(IUiView* pCurrentView, const Vector3d& pos )
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(pCurrentView, L"空指针pCurrentView",L"GDMP",L"2024-03-30");

    // 暂时先以全局设置为准，等设计好了之后再修改
    OwnerPtr<ISnapSettings> opSnapSettings = ISnapSettings::GetGlobalSnapSettings()->Clone();
    DBG_WARN_AND_RETURN_VOID_UNLESS(opSnapSettings.get(), L"空指针opSnapSettings.get()",L"GDMP",L"2024-03-30");
    opSnapSettings->SetIsForceHorizontalOrVertical(IsKeyAndButtonPressed(VK_SHIFT));

    //////////////////////////////////////////////////////////////////////////
    // TODO：暂时保留，因为产品和AppAbmp很多地方在初始配置SnapContext过程中SetIsSnapOff、或者SetCanSnap3dPoint调用
    //              按当前设计，应该迁移到ConfigSnapSettings中，但是影响产品日志和修改地方比较多，所以先用调整顺序解决(原来在ConfigSnapSettings后调用）。
    // GBMP-42001 【中维】【拾取捕捉】SetIsSnapOff在PickPointActionConfig中，无法再设置回false
    DBG_WARN_AND_RETURN_VOID_UNLESS(m_opSnapContext && m_opSnapContext.get(), L"SnapContext is nullptr!",L"GDMP",L"2024-03-30");
    OwnerPtr<ISnapSettings> snapSettings = m_opSnapContext->GetSnapSettings();
    if (snapSettings->IsSnapOff())
        opSnapSettings->SetIsSnapOff(true);
    if (snapSettings->CanSnap3dPoint())
        opSnapSettings->SetCanSnap3dPoint(true);
    //////////////////////////////////////////////////////////////////////////

    //用户可以通过m_opPickConfig的接口ConfigureOrthogonalMode配置一些用户定制的行为（如：配置拾取时的正交模式）
    if (m_opPickPointActionConfigure.get())
    {
        m_opPickPointActionConfigure->ConfigSnapSettings(opSnapSettings.get());
    }

    const IModelView* pModelView = pCurrentView->GetModelView();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pModelView, L"pModelView is nullptr! ",L"GDMP",L"2024-03-30");
    if (Snap3DAxialDirectionLine && pModelView->GetViewType() == BuiltInViewType::ThreeDimensional)
    {
        opSnapSettings->SetCanSnap3dPoint(true);
        opSnapSettings->SetCanSnap3DAxialDirectionLine(true);
        
        // 默认设置的坐标系是原点在(0,0,0)，三个方向同世界坐标系；
        // 关闭水平竖直捕捉的目的: 水平竖直捕捉优先级更高导致后面从捕捉中拿首个snap时，是水平竖直捕捉，而非坐标系轴向线捕捉
        opSnapSettings->SetCanSnapHorizontalVerticalLine(false);
    }

    if (OpenSnap3DParallel && pModelView->GetViewType() == BuiltInViewType::ThreeDimensional)
    {
        opSnapSettings->SetCanSnap3DParallel(true);
        opSnapSettings->SetCanSnap3dPoint(true);
    }

    if (UseSnapEdgeLineExtension && pModelView->GetViewType() == BuiltInViewType::ThreeDimensional) {
        opSnapSettings->SetCanSnap3DExtension(true);
    }

    if (OpenSmartColorForSnapPrompt)
        m_opSnapContext->SetUseSmartAntiBackgroundColorForSnapPrompt(true);

    if (CloseRemoteSnapsDeduplication)
        m_opSnapContext->SetRemoveDuplicateRemoteSnaps(false);

    if (SnapTangencyPointWhenCondition)
    {
        opSnapSettings->DisableAllSnaps();
        opSnapSettings->SetCanSnapTangent(true);
    }

    UiSnapUtils::InitSnapContextFromUiView(m_opSnapContext.get(), pCurrentView, m_pped.m_planeType);//需要更新视图

    m_opSnapContext->SetInputPoint(pos);
    m_opSnapContext->SetSnapSettings(opSnapSettings.get());
    if (SnapDirDeterminedByModelView)
        m_opSnapContext->SetIsDirectionDeterminedByModelView(true);
    m_opSnapCandidates = Snapper::Snap(m_opSnapContext.get());
    DBG_WARN_AND_RETURN_VOID_UNLESS(m_opSnapCandidates, L"空指针m_opSnapCandidates",L"GDMP",L"2024-03-30");
    const ISnap* snap = m_opSnapCandidates->GetCurrentSnap();
    if (snap)
    {
        SAFE_INIT_POINTER(m_pped.pSnap, snap->Clone());
        SAFE_INIT_POINTER(m_pped.pPickedPoint, snap->GetSnappedPoint());

        SetPromptMessage(snap->GetLongPrompt());
        m_isCaught = true;
    }
    else
    {
        Vector3d posOnWorkPlane = pos;
        ActionBase::ProjectPositionOnWorkPlane(pCurrentView, pos, posOnWorkPlane);
        SAFE_INIT_POINTER(m_pped.pSnap, nullptr);
        if (m_pped.m_planeType == PickPointExchangeData::SnapPlaneType::WorkPlane)
        {
            SAFE_INIT_POINTER(m_pped.pPickedPoint, posOnWorkPlane);
        }
        else
        {
            Vector3d posOnSnapPlane = pos;
            if (m_pped.m_planeType == PickPointExchangeData::SnapPlaneType::SnapPlane)
            {
                ProjectPositionOnSnapPlane(pos, posOnSnapPlane, m_opSnapContext.get(), pCurrentView);
                SAFE_INIT_POINTER(m_pped.pPickedPoint, posOnSnapPlane);
            }
            else
            {
                ProjectPositionOnSnapPlane(pos, posOnSnapPlane);
                SAFE_INIT_POINTER(m_pped.pPickedPoint, posOnSnapPlane);
            }
        }

        SetPromptMessage(L"");
        m_isCaught = false;
    }
    if (m_opCoordinateInputWidget)
    {
        ISnapRender::Get()->Draw(snap, SnapTextPositionType::UpperRight);
    }
    else
    {
        ISnapRender::Get()->Draw(snap, SnapTextPositionType::LowerRight);
    }
    UpdateView();
}

void SamplePickPointAction::ClearSnap()
{
    //清理返回的捕捉数据
    SAFE_INIT_POINTER(m_pped.pPickedPoint, Vector3d());
    m_pped.mousePoint = Vector3d();

    m_opSnapCandidates = nullptr;
    ISnapRender::Get()->ClearSnapRenderData();

    //复位：是否捕捉到
    m_isCaught = false;
    UpdateView();
}

bool SamplePickPointAction::IsPickVisible()
{
    if (IsKeyAndButtonPressed(VK_MBUTTON))
        return false;
    return true;
}

bool SamplePickPointAction::OnMovePoint( IUiView* pCurrentView,const Vector3d& pos )
{
    // 处于坐标输入状态，屏蔽捕捉
    if (m_opCoordinateInputWidget && m_opCoordinateInputWidget->IsInInputState())
        return true; 

    ITemporaryDimensionManager *pTemporaryDimensionMgr = ITemporaryDimensionManager::Get();
    if (pTemporaryDimensionMgr)
    {
        ITemporaryDimensionHandler *pITemporaryDimensionHandler = pTemporaryDimensionMgr->GetCurrentTemporaryDimensionHandler();
        if (pITemporaryDimensionHandler && !pITemporaryDimensionHandler->IsInputWidgetEditable() && pITemporaryDimensionHandler->IsInInputState())
        {
            // 处于编辑状态却不可编辑，将输入框隐藏
            pITemporaryDimensionHandler->HideInputWidget();
        }
    }

    ActionBase::OnMovePoint(pCurrentView, pos);

    // TIMER_START(MovePointTimer);
    m_IsTabReset = false;
    DBG_WARN_AND_RETURN_UNLESS(m_pped.pPickedPoint != nullptr, false,L"m_pped.pPickedPoint拾取点为空",L"GDMP",L"2024-03-30");
    Vector3d oldPickedPnt = *(m_pped.pPickedPoint);

    if (m_moveBeforeSnapCallBack)
        m_moveBeforeSnapCallBack(pCurrentView, pos, m_opSnapContext.get());

    // 计算拾取捕捉点
    if (IsPickVisible())
    {
        // TIMER_START(CalculateReturnResult);
        CalculateReturnResult(pCurrentView, pos);
        // TIMER_END(CalculateReturnResult);
    }

    // 处于坐标显示状态，更新坐标显示值
    {
        if (m_opCoordinateInputWidget && !m_opCoordinateInputWidget->IsInInputState())
        {
            if (m_wpXCoordEdit && m_wpXCoordEdit->IsLock())
            {
                m_pped.pPickedPoint->SetX(oldPickedPnt.X());
            }
            if (m_wpYCoordEdit && m_wpYCoordEdit->IsLock())
            {
                m_pped.pPickedPoint->SetY(oldPickedPnt.Y());
            }
            if (m_wpZCoordEdit && m_wpZCoordEdit->IsLock())
            {
                m_pped.pPickedPoint->SetZ(oldPickedPnt.Z());
            }

            Vector3d pickedPnt = *m_pped.pPickedPoint;
            Vector3d pnt = m_opWorkPlane ? m_opWorkPlane->GetCoordinate().GetLocalPoint(pickedPnt) : pickedPnt;

            m_wpXCoordEdit ? m_wpXCoordEdit->SetText(StringUtil::ToWString(pnt.X(),3)) : false ;
            m_wpYCoordEdit ? m_wpYCoordEdit->SetText(StringUtil::ToWString(pnt.Y(),3)) : false ;
            m_wpZCoordEdit ? m_wpZCoordEdit->SetText(StringUtil::ToWString(pnt.Z(),3)) : false ;
            m_opCoordinateInputWidget->Refresh();
        }
    }
    
    // 拾取点后处理
    // TIMER_START(MoveCallback);
    if(m_moveCallback)
        m_moveCallback(pCurrentView, *m_pped.pPickedPoint, m_pped.mousePoint);
    // TIMER_END(MoveCallback);

    // TIMER_END_AND_REPORT_AND_RESET(MovePointTimer);
    return true;
}

bool SamplePickPointAction::IsCaught() const
{
    return m_isCaught;
}

ISnapContext* SamplePickPointAction::GetSnapContext() const
{ 
    return const_cast<gcmp::ISnapContext*>(m_opSnapContext.get());
}

bool SamplePickPointAction::SetSnapContext(const ISnapContext* snapContext)
{ 
    m_opSnapContext = TransferOwnership(snapContext->Clone());
    return true;
}

bool SamplePickPointAction::OnKeyDown(IUiView* pCurrentView, int nChar)
{
    if (m_OnKeyDownCallback)
    {
        //返回值为ture，退出OnKeyDown； 返回值为false，继续执行OnKeyDown的默认行为
        if (m_pped.pPickedPoint && m_OnKeyDownCallback(nChar, pCurrentView, *m_pped.pPickedPoint, m_pped.mousePoint))
        {
            return true;
        }
    }

    if (VK_TAB == nChar) //tab
    {
        DBG_WARN_AND_RETURN_UNLESS(m_opSnapCandidates, false, L"空指针m_opSnapCandidates",L"GDMP",L"2024-03-30");
        const std::vector<const ISnap*>& snapResults = m_opSnapCandidates->GetCandidates();
        int numResults = (int)(snapResults.size());
        int needFilterSnapNum = 0;
        if (!m_filterSnapTypeForTabKeySwitch.empty())
        {
            FOR_EACH(snap, snapResults)
            {
                if (snap && 
                    std::find(m_filterSnapTypeForTabKeySwitch.begin(), m_filterSnapTypeForTabKeySwitch.end(), snap->GetSnapType()) != m_filterSnapTypeForTabKeySwitch.end())
                {
                    needFilterSnapNum++;
                }
            }
        }
        if (numResults > 1 && numResults > needFilterSnapNum)
        {
            const ISnap* snap = m_opSnapCandidates->UpdateCurrentSnapToNext();
            DBG_WARN_AND_RETURN_UNLESS(snap, false, L"空指针snap",L"GDMP",L"2024-03-30");

            if (!m_filterSnapTypeForTabKeySwitch.empty())
            {
                while (std::find(m_filterSnapTypeForTabKeySwitch.begin(), m_filterSnapTypeForTabKeySwitch.end(), snap->GetSnapType()) != m_filterSnapTypeForTabKeySwitch.end())
                {
                    snap = m_opSnapCandidates->UpdateCurrentSnapToNext();
                    DBG_WARN_AND_RETURN_UNLESS(snap, false, L"空指针snap",L"GDMP",L"2024-03-30");
                }
            }

            m_isCaught = true;
            std::wstring desp = snap->GetLongPrompt();
            SetPromptMessage(desp);

            SAFE_INIT_POINTER(m_pped.pSnap, snap->Clone());
            SAFE_INIT_POINTER(m_pped.pPickedPoint, snap->GetSnappedPoint());

            if (m_opCoordinateInputWidget)
            {
                ISnapRender::Get()->Draw(snap, SnapTextPositionType::UpperRight);
            }
            else
            {
                ISnapRender::Get()->Draw(snap, SnapTextPositionType::LowerRight);
            }

            if (m_moveCallback)
                m_moveCallback(pCurrentView, snap->GetSnappedPoint(), m_pped.mousePoint);
            UpdateView();
            return true;
        }
    }
    else if (m_opPickPointActionConfigure)
    {
        DBG_WARN_AND_RETURN_UNLESS(m_opSnapContext.get(), false, L"空指针m_opSnapContext.get()",L"GDMP",L"2024-03-30");
        OwnerPtr<ISnapSettings> opSnapSettings = m_opSnapContext->GetSnapSettings();
        DBG_WARN_AND_RETURN_UNLESS(opSnapSettings.get(), false, L"空指针opSnapSettings.get()",L"GDMP",L"2024-03-30");
        bool beforeState = opSnapSettings->IsForceHorizontalOrVertical();
        m_opPickPointActionConfigure->ConfigSnapSettings(opSnapSettings.get());
        //用户配置前后正交模式状态变化，说明正交模式被激活
        if (opSnapSettings->IsForceHorizontalOrVertical() ^ beforeState)
        {
            OnMovePoint(pCurrentView, m_opSnapContext->GetInputPoint());
            UpdateView();
        }
        //如果用户配置了正交模式，但需要保持默认行为不便，则需要使用下面的逻辑
        else if (16 == nChar)
        {
            Vector3d pos;
            OnMovePoint(pCurrentView, m_opSnapContext->GetInputPoint());
            UpdateView();
        }
    }
    else if (16 == nChar)
    {
        Vector3d pos;
        OnMovePoint(pCurrentView, m_opSnapContext->GetInputPoint());
        UpdateView();
    }

    if (m_opCoordinateInputWidget)
    {
        if (VK_RETURN == nChar || VK_SPACE == nChar)
        {
            if (JournalUtils::IsInReplay())
            {
                if (m_wpXCoordEdit)
                    m_pped.pPickedPoint->SetX(StringUtil::ToNumber<double>(m_wpXCoordEdit->GetText()));
                if (m_wpYCoordEdit)
                    m_pped.pPickedPoint->SetY(StringUtil::ToNumber<double>(m_wpYCoordEdit->GetText()));
                if (m_wpZCoordEdit)
                    m_pped.pPickedPoint->SetZ(StringUtil::ToNumber<double>(m_wpZCoordEdit->GetText()));
            }
            m_pped.pPickedPoints->push_back(*m_pped.pPickedPoint);
            ISnapRender::Get()->ClearSnapRenderData();
            if (m_opCoordinateInputWidget && m_opCoordinateInputWidget->IsUserCustomInput())
            {
                SetUserCustomInput();
                SAFE_INIT_POINTER(m_pped.pUserCancelled, true);
                MarkFinishStatus(ActionFinishStatus::Cancelled);
                MarkFinishReason(ActionFinishReason::UserInputString);
            }
            else
            {
                SAFE_INIT_POINTER(m_pped.pUserCancelled, false);
                MarkFinishStatus(ActionFinishStatus::Successful);
            }

            UpdateView();
            m_opViewMouseHandler.reset(nullptr);
            return true;
        }
    }

    return ActionBase::OnKeyDown(pCurrentView,nChar);
}

bool SamplePickPointAction::OnReceiveViewInputData(IUiView* pCurrentView, const ActionViewInput& inputParam)
{
    DBG_WARN_AND_RETURN_UNLESS(pCurrentView != nullptr, false, L"pCurrentView不能为空",L"GDMP",L"2024-03-30");
    IModelView* curModelView = pCurrentView->GetModelView();
    DBG_WARN_AND_RETURN_UNLESS(curModelView != nullptr, false, L"curModelView不能为空",L"GDMP",L"2024-03-30");
    OwnerPtr<IPlane> curGPlane = curModelView->GetWorkPlane();
    DBG_WARN_AND_RETURN_UNLESS(curGPlane, false, L"当前视图没有找到工作平面",L"GDMP",L"2024-03-30");

    //////////////////////////////////////////////////////////////////////////
    if (!inputParam.InputString.empty()) 
    {
        m_opActionOutputData = NEW_AS_OWNER_PTR(PickPointActionOutputData, true, inputParam.InputType, inputParam.InputVal, inputParam.InputString);
        MarkFinishStatus(ActionFinishStatus::Cancelled);
        MarkFinishReason(ActionFinishReason::UserInputString);
        return true;
    }
    //////////////////////////////////////////////////////////////////////////

    // 1.准备坐标
    std::vector<Vector3d> oPosPts;
    bool isPrepared = TemporaryDimensionCommons::PreparePosForViewInput(inputParam, *m_pped.pPickedPoints, *m_pped.pPickedPoint, oPosPts);

    // 2.计算位置
    Vector3d newPt;
    std::wstring notificationStr;

    Coordinate3d dimCoord;
    ITemporaryDimensionHandler* pTempDimHandler = ITemporaryDimensionManager::Get()->GetCurrentTemporaryDimensionHandler();
    pTempDimHandler->GetCoordinate(dimCoord);
    const IGraphicsPlane& graphicsPlane = m_opSnapContext->GetSnapPlane();
    bool isCalculated = isPrepared && TemporaryDimensionCommons::CalculateNewPosForViewInput(inputParam, oPosPts, dimCoord, newPt, notificationStr);
    if (isCalculated == false)
    {
        DBG_WARN_UNLESS(!notificationStr.empty(), L"提示消息字符串为空！",L"GDMP",L"2024-03-30");
        // 触发警告弱提示
        UiNotificationUtils::PostNotification(NotificationTypes::WarningNotificationType, notificationStr);
        return false;
    }

    // 3.捕捉过滤
    OwnerPtr<ISnapSettings> snapSettingsOriginal = m_opSnapContext->GetSnapSettings();
    OwnerPtr<ISnapSettings> snapSettingsTemp = m_opSnapContext->GetSnapSettings();
    bool isSuperposition = std::find(m_pped.pPickedPoints->begin(), m_pped.pPickedPoints->end(), newPt) != m_pped.pPickedPoints->end();
    if (isSuperposition)
    {
        DoSnap(pCurrentView, newPt);
    }
    else
    {
        // 若没有点重合, 则不捕捉端点
        snapSettingsTemp->SetCanSnapEndPoint(false);
        m_opSnapContext->SetSnapSettings(snapSettingsTemp.get());
        DoSnap(pCurrentView, newPt);
        m_opSnapContext->SetSnapSettings(snapSettingsOriginal.get());
        *m_pped.pPickedPoint = newPt;
    }

    // 4.触发回调
    //bool isMoveCallback = isCalculated && OnMoveCallback(pCurrentView);

    // 5.确认输入
    if (isCalculated && TemporaryDimensionCommons::IsInputConfirmed(inputParam))
    {
        m_pped.pPickedPoints->push_back(*m_pped.pPickedPoint);
        SAFE_INIT_POINTER(m_pped.pUserCancelled, false);
        MarkFinishStatus(ActionFinishStatus::Successful);
        UpdateView();
    }

    // 将用户输入的数据传出去。
    m_opActionOutputData = NEW_AS_OWNER_PTR(PickPointActionOutputData, true, inputParam.InputType, inputParam.InputVal, inputParam.InputString);

    return isCalculated;
}

void SamplePickPointAction::GetActionOutput(ActionOutput& param) const
{
    ActionBase::GetActionOutput(param);
    //临时方案，解决绘制圆弧时右键确定拾取结果不正确
    if (param.FinishStatus == ActionFinishStatus::Successful && (param.FinishReason == ActionFinishReason::RButtonDown || 
        param.FinishReason == ActionFinishReason::RButtonUp))
    {
        m_pped.pPickedPoints->emplace_back(*m_pped.pPickedPoint);
    }

    if (!m_opActionOutputData.get())
    {
        return;
    }
    const IActionOutputData* pOutputData = m_opActionOutputData.get();

    // 处理用户输入
    std::wstring inputStr = dynamic_cast<const PickPointActionOutputData*>(pOutputData)->GetInputString();
    if (!inputStr.empty())
    {
        param.InputString = inputStr;
        param.FinishReason = ActionFinishReason::UserInputString;
    }
    param.ActionOutputData = TransferOwnership(pOutputData->Clone());
}

bool SamplePickPointAction::OnMoveCallback(gcmp::IUiView* pCurrentView)
{
    if(m_moveCallback)
    {
        m_moveCallback(pCurrentView, *m_pped.pPickedPoint, m_pped.mousePoint);
        return true;
    }

    return false;
}

void SamplePickPointAction::OnChildActionFinished(IUiView* pCurrentView, const ActionOutput& childActionReturnParam)
{ 
    //(1) 有时候需要知道子Action是否被取消了
    //(2) 有时候会恢复一下启动的状态
    if (childActionReturnParam.FinishStatus == ActionFinishStatus::Cancelled && 
        childActionReturnParam.IsParentActionNeedCancel)
    {
        //目前此Action只会启动拖动辅助点的子Action
        //如果子Action取消了，当前Action也取消
        //(根据子Action的返回参数来决定继续还是取消)
        ActionCancelled();
    }
}

bool SamplePickPointAction::OnKeyUp(gcmp::IUiView* pCurrentView, int nChar)
{
    //因为发版时间关系，没有处理Shift激活正交模式的情况，后面应该加上
    if (m_opPickPointActionConfigure)
    {
        OwnerPtr<ISnapSettings> opSnapSettings = m_opSnapContext->GetSnapSettings();
        DBG_WARN_AND_RETURN_UNLESS(opSnapSettings.get(), false, L"空指针opSnapSettings.get()",L"GDMP",L"2024-03-30");
        DBG_WARN_AND_RETURN_UNLESS(m_opSnapContext.get(), false, L"空指针m_opSnapContext.get()",L"GDMP",L"2024-03-30");
        bool beforeState = opSnapSettings->IsForceHorizontalOrVertical();
        m_opPickPointActionConfigure->ConfigSnapSettings(opSnapSettings.get());
        //用户配置前后正交模式状态变化，说明正交模式被激活
        if (opSnapSettings->IsForceHorizontalOrVertical() ^ beforeState)
        {
            OnMovePoint(pCurrentView, m_opSnapContext->GetInputPoint());
            UpdateView();
        }
    }
    return ActionBase::OnKeyUp(pCurrentView, nChar);
}

bool SamplePickPointAction::RegisterEditCallBack(IPickPointAction::EditCallback &editCallback)
{
    m_editCallback = editCallback;
    return true;
}

bool SamplePickPointAction::ProjectPositionOnSnapPlane(const Vector3d& pos, Vector3d& projectedPos, ISnapContext* pSnapContext, const IUiView* pCurrentView) const
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pSnapContext != nullptr, L"pSnapContext为空",L"GDMP",L"2024-03-30");

    OwnerPtr<ILine3d> opRay = UiViewUtility::WorldPositionToWorldRay(pCurrentView, pos);
    const IGraphicsPlane& pGraphicsPlane = pSnapContext->GetSnapPlane();

    return AlgorithmIntersect::Intersect(opRay.get(), pGraphicsPlane.GetGmIPlane(),  projectedPos);
}

void SamplePickPointAction::ActionCancelled()
{
    //通知基类，会标记当前Action结束
    ActionBase::ActionCancelled();

    ISnapRender::Get()->ClearSnapRenderData();
    SAFE_INIT_POINTER(m_pped.pUserCancelled, true);
}

//确保OnMovePoint 和 Click 返回的点相同
void SamplePickPointAction::CalculateReturnResult(IUiView* pCurrentView, const Vector3d& pos)
{
    //   /* 杨斌 2015-09-18
    //   *移动点时进行点的捕捉，捕捉通过计算点与候选物体的距离大小
    //   *若选择到，则显示为被捕捉到的临时显示(点)
    //   *若移远后不想捕捉，则取消显示临时点，且设标志位为未捕捉

    //计算与工作平面的交点(相当于鼠标所在点)
    Vector3d posOnWorkPlane;
    ActionBase::ProjectPositionOnWorkPlane(pCurrentView, pos, posOnWorkPlane);

    if (m_pped.m_pickElementBeforeSnapConcretePoint) //在捕捉过程中优先考虑拾取
    {
        DoPick(pCurrentView, pos);
        //如果拾取到了东西则放弃捕捉(否则进行正常捕捉)
        if (IPickCandidates::Get()->GetCount() > 0)
        {
            //清理之前的捕捉信息
            ClearSnap();

            SAFE_INIT_POINTER(m_pped.pPickedPoint, posOnWorkPlane);
        }
        else
        {
            DoSnap(pCurrentView, pos);
        }
    }
    else  //仅做捕捉
    {
        DoSnap(pCurrentView, pos);
    }

    m_pped.mousePoint = pos;
}

bool SamplePickPointAction::SetFirstPoint(const Vector3d& firstPoint )
{
    m_opSnapContext->SetFirstPoint(&firstPoint);
    return true;
}

bool SamplePickPointAction::StartCoordinateInput(OwnerPtr<IPlane> opWorkPlane/* = nullptr*/, bool userCustomInput/* = false*/)
{
    if (!m_opCoordinateInputWidget)
    {
        OwnerPtr<ICoordinateInputDefinition> opXCoordEdit = ICoordinateInputDefinition::Create(L"xCoord", L"");
        OwnerPtr<ICoordinateInputDefinition> opYCoordEdit = ICoordinateInputDefinition::Create(L"yCoord", L"");
        m_wpXCoordEdit = opXCoordEdit.get();
        m_wpYCoordEdit = opYCoordEdit.get();
        std::vector<OwnerPtr<ICoordinateInputDefinition>> coordLineEdits;
        opXCoordEdit->GetEvent()->Add(this);
        opYCoordEdit->GetEvent()->Add(this);
        coordLineEdits.push_back(TransferOwnership(opXCoordEdit));
        coordLineEdits.push_back(TransferOwnership(opYCoordEdit));

        if (m_pped.m_pickPointType == PickPointExchangeData::PickPointType::ThreeDimensionPoint)
        {
            OwnerPtr<ICoordinateInputDefinition> opZCoordEdit = ICoordinateInputDefinition::Create(L"zCoord", L"");
            m_wpZCoordEdit = opZCoordEdit.get();
            m_wpZCoordEdit->GetEvent()->Add(this);
            coordLineEdits.push_back(TransferOwnership(opZCoordEdit));
        }
        if (opWorkPlane)
        {
            m_opWorkPlane = TransferOwnership(opWorkPlane);
        }

        m_opCoordinateInputWidget = IActionCoordinateInputWidget::Create(GetMouseTooltipMessage(), TransferOwnership(coordLineEdits), m_editCallback, userCustomInput);
        SetMouseTooltipMessage(L"");

        m_opViewMouseHandler = NEW_AS_OWNER_PTR(UiViewMouseEventHandler, m_opCoordinateInputWidget.Get());
        IUiDocumentViewManager* pUiDocViewMgr = IUiDocumentViewManager::Get();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pUiDocViewMgr, L"pUiDocViewMgr为空",L"GDMP",L"2024-03-30");
        IUiView* pCurrentUiView = pUiDocViewMgr->GetCurrentUiView();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pCurrentUiView != nullptr, L"pCurrentUiView不能为空",L"GDMP",L"2024-03-30");
        if (IUiViewMouseEvent* pUiViewMouseEvent = pCurrentUiView->GetUiViewMouseEvent())
        {
            pUiViewMouseEvent->Add(m_opViewMouseHandler.get());
        }

        return true;
    }
    return false;
}

std::wstring SamplePickPointAction::GetCursorPath() const
{
    std::wstring cursorPath;
    if (m_cursorPathCallBack)
        m_cursorPathCallBack(cursorPath);

    if (cursorPath.empty())
        cursorPath = ActionBase::GetCursorPath();

    return cursorPath;
}

bool SamplePickPointAction::SetCursorPathCallBack(CursorPathCallBack callBack)
{
    m_cursorPathCallBack = callBack;
    return true;
}

void SamplePickPointAction::On(ILineEditEventArgs* pArgs)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(pArgs, L"pArgs为空",L"GDMP",L"2024-03-30");

    if (pArgs->GetType() == LineEditEventType::EditingFinished)
    {
        std::wstring inputStr = pArgs->GetText();
        if (inputStr.empty())
            return;

        // 字符解析数字
        {
            bool isOK = false;
            double dVal = StringUtil::ToNumber<double>(inputStr, &isOK);  //用户输入字符串，转换值不成功
            // 如果有参照面，捕捉点转参照面局部坐标系
            Vector3d pnt = (m_opWorkPlane ? m_opWorkPlane->GetCoordinate().GetLocalPoint(*m_pped.pPickedPoint) : *m_pped.pPickedPoint);
            if (m_wpXCoordEdit && pArgs->GetControlId() == m_wpXCoordEdit->GetId())
            {
                m_wpXCoordEdit->SetIsEditingFinished(true);
                if(isOK) pnt.SetX(dVal);
            }
            if (m_wpYCoordEdit && pArgs->GetControlId() == m_wpYCoordEdit->GetId())
            {
                m_wpYCoordEdit->SetIsEditingFinished(true);
                if (isOK) pnt.SetY(dVal);
            }
            if (m_wpZCoordEdit && pArgs->GetControlId() == m_wpZCoordEdit->GetId())
            {
                m_wpZCoordEdit->SetIsEditingFinished(true);
                if (isOK) pnt.SetZ(dVal);
            }
            // 如果有参照面，局部坐标点转世界坐标系给当前捕捉结果
            *m_pped.pPickedPoint = (m_opWorkPlane ? m_opWorkPlane->GetCoordinate().GetWorldPoint(pnt) : pnt);
        }
    }
}

void SamplePickPointAction::SetUserCustomInput()
{
    if (m_opCoordinateInputWidget && m_opCoordinateInputWidget->IsUserCustomInput())
    {
        ActionViewInputType inputType = ActionViewInputType::Invalid;
        std::wstring coordInputStr;
        if (m_wpXCoordEdit)
        {
            coordInputStr = m_wpXCoordEdit->IsEditingFinished()?m_wpXCoordEdit->GetText(): L"";
            m_wpXCoordEdit->SetIsEditingFinished(false);
        }
        if (m_wpYCoordEdit)
        {
            coordInputStr += L"," + (m_wpYCoordEdit->IsEditingFinished()?m_wpYCoordEdit->GetText() : L"");
            m_wpYCoordEdit->SetIsEditingFinished(false);
        }
        if (m_wpZCoordEdit)
        {
            coordInputStr += L"," + (m_wpZCoordEdit->IsEditingFinished()?m_wpZCoordEdit->GetText() : L"");
            m_wpZCoordEdit->SetIsEditingFinished(false);
        }

        m_opActionOutputData = NEW_AS_OWNER_PTR(PickPointActionOutputData, true, ActionViewInputType::Invalid, 0.0, coordInputStr);
        MarkFinishReason(ActionFinishReason::UserInputString);
    }
}

bool SamplePickPointAction::ProjectPositionOnSnapPlane(const Vector3d& pos, Vector3d& projectedPos) const
{
    const IGraphicsPlane& pGraphicsPlane = m_opSnapContext->GetSnapPlane();

    Vector2d uvParameter = Vector2d::Zero;
    return AlgorithmProject::Project(pos, pGraphicsPlane.GetGmIPlane(), uvParameter, projectedPos);
}

//////////////////////////////////////////////////////////////////////////
void UiViewMouseEventHandler::On(IUiViewMouseEventArgs* pArgs)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(pArgs, L"pArgs为空",L"GDMP",L"2024-03-30");

    UiViewMouseEventType mouseEventType = pArgs->GetType();

    if (m_pCoordWidget)
    {
        if (mouseEventType == UiViewMouseEventType::MiddleButtonDown)
        {
            m_pCoordWidget->Hide();
        }
        else if (mouseEventType == UiViewMouseEventType::MiddleButtonUp)
        {
            m_pCoordWidget->Show();
        }
    }
    
}

bool SamplePickPointAction::SetOnKeyDownCallback(IPickPointAction::OnKeyDownCallback callback)
{
    m_OnKeyDownCallback = callback;
    return true;
}

gcmp::OwnerPtr<IPickPointAction> SamplePickPointAction::Create(PickPointExchangeData &exchangeData, MoveCallback moveCallback /*= nullptr*/,
    ActionFinishedMode enActionFinishedMode /*= ActionFinishedMode::LButtonDown*/, bool isReturnKeyNeedCanceled, OwnerPtr<IPickPointActionConfig> opPickConfig)
{
    return NEW_AS_OWNER_PTR(SamplePickPointAction, exchangeData, moveCallback, enActionFinishedMode, isReturnKeyNeedCanceled, TransferOwnership(opPickConfig));
}